package com.leetcode.basic.synchronize;

import org.junit.Test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 《volatile和synchronized的区别》 https://blog.csdn.net/suifeng3051/article/details/52611233
 * <p>
 * 《volatile 解决了什么问题？》https://cloud.tencent.com/developer/article/1362756
 * <p>
 * <p>
 * 简短的总结一下，主要解决 2 个问题：
 * 1.禁止编译器优化而重排序指令。
 * 2.对 volatile 修饰的变量值，保证线程读取到的值是最新的，而不是寄存器中缓存的值。
 * <p>
 * 《深入理解Volatile》https://juejin.im/post/5acdb75951882555635ead2c
 * <p>
 * 《正确使用 Volatile 变量》https://www.ibm.com/developerworks/cn/java/j-jtp06197.html
 */
public class VolatileDemo {

	volatile int v = 0;
	int           n      = 0;
	List<Integer> list   = Collections.synchronizedList(new ArrayList<>());
	boolean       isLoop = true;

	@Test
	public void testVolatile() throws InterruptedException {
		Thread th0 = new VolatileTh();
		Thread th1 = new VolatileTh();

		th0.start();
		th1.start();

		Thread.sleep(10);
		isLoop = false;

		th0.join();
		th1.join();

		while (th0.isAlive() || th1.isAlive()) {}

		System.out.println(th0.getState());
		System.out.println(th1.getState());

		printList();
	}

	@Test
	public void testNormal() throws InterruptedException {
		// 两条线程不断k++，如果k没有volatile，并发时k值不确定
		Thread th0 = new Th();
		Thread th1 = new Th();

		th0.start();
		th1.start();

		Thread.sleep(10);
		isLoop = false;

		th0.join();
		th1.join();

		while (th0.isAlive() || th1.isAlive()) {}

		System.out.println(th0.getState());
		System.out.println(th1.getState());

		printList();
	}

	private void printList() {
		List<String> contents = new ArrayList<>();

		for (int i = 1; i < list.size(); i++) {
			int last    = list.get(i - 1);
			int current = list.get(i);

			if (current <= last) {
				contents.add("[i-1]=" + last);
				contents.add("[i]=" + current);
				contents.add("");
			}
		}

		if (contents.size() > 500) {
			contents = contents.subList(0, 500);
		}

		for (String content : contents) {
			System.out.println(content);
		}
	}

	////////////////////////////////////////////////

	class Th extends Thread {

		public Th() {
			super(() -> {
				// 不断对k操作
				while (isLoop) {
					n++;
					list.add(n);
				}
			});
		}
	}

	class VolatileTh extends Thread {

		public VolatileTh() {
			super(() -> {
				// 不断对k操作
				while (isLoop) {
					v++;
					list.add(v);
				}
			});
		}
	}

}
